// vb13.v
// Verilog version, rewritten by Li Shen, Aug 2002
// Institute of Computing Technology, Chinese Academy of Sciences
// The original VHDL version is b13.vhd from Politecnico di Torino

module b13 (clock,reset,eoc,dsr,data_in,
            soc,load_dato,add_mpx2,mux_en,error,data_out,canale);
input clock;
input reset;
input eoc;
input dsr;
input [7:0] data_in;
output soc;
output load_dato;
output add_mpx2;
output mux_en; 
output error;
output data_out;
output [3:0] canale;
/////
wire clock;
wire reset;
wire eoc;
wire dsr;
wire [7:0] data_in;
reg soc;
reg load_dato;
reg add_mpx2;
reg mux_en; 
reg error;
reg data_out;
reg [3:0] canale;
/////
parameter GP001=0, GP010=1, GP011=2, GP100=3;
parameter GP100w=4, GP101=5, GP110=6, GP111=7;
parameter GP01=0, GP10=1, GP11=2, GP11w=3;
parameter START_BIT=0, STOP_BIT=1, BIT0=2, BIT1=3, BIT2=4;
parameter BIT3=5, BIT4=6, BIT5=7, BIT6=8, BIT7=9;
parameter G_IDLE=0, G_LOAD=1, G_SEND=2, G_WAIT_END=3;
reg mpx, rdy, tre, send, load, shot, confirm;
reg send_en, send_data, tx_end;
reg [2:0] S1;
reg [1:0] S2;
reg [3:0] next_bit;
reg [1:0] itfc_state;
reg [7:0] out_reg;
reg [9:0] tx_conta;
/////
reg [3:0] conta_tmp;

always @(posedge clock)
begin
  if (reset)
  begin
    	S1 <= GP001;
	soc <= 0;
	canale <= 0;
	conta_tmp = 0;
	send_data <= 0;
	load_dato <= 0;
	mux_en <= 0;
  end
  else
  case (S1)
  GP001:
	begin
	 mux_en <= 1;
	 S1 <= GP010;
	end
  GP010:
	S1 <= GP011;
  GP011:
	begin
	  soc <= 1;	
	  S1 <= GP101;
	end
  GP101:
	if (eoc)
	  S1 <= GP101;
	else
	begin
	  load_dato <= 1;
	  S1 <= GP110;
	  mux_en <= 0;
	end
  GP110:
	begin
	  load_dato <= 0;
	  soc <= 0;			
	  conta_tmp = conta_tmp+1;
	  if (conta_tmp == 8)
	    conta_tmp = 0;
	  canale <= conta_tmp;
	  S1 <= GP111;
	end
  GP111:
	begin
	  send_data <= 1;
	  S1 <= GP100w;
	end
  GP100w:
	S1 <= GP100;
  GP100:
	if (!rdy)
	  S1 <= GP100;
	else
	begin
	  S1 <= GP001;
	  send_data <= 0;
	end
  endcase
end
/////
always @(posedge clock)
begin
  if (reset)
  begin
	S2 <= GP01;
	rdy <= 0;
	add_mpx2 <= 0;
	mpx <= 0;
	shot <= 0;
  end
  else
  case (S2)
  GP01:
	if (send_data)
	begin
	  rdy <= 1;
	  S2 <= GP10;
	end
	else
	  S2 <= GP01;
  GP10:
	begin
	  shot <= 1;
	  S2 <= GP11;
	end
  GP11:
	if (!confirm)
	begin
	  shot <= 0;
	  S2 <= GP11;
	end
	else
	begin
	  if (!mpx)
	  begin
	    add_mpx2 <= 1;
	    mpx <= 1;
	    S2 <= GP10;
	  end
	  else
	  begin
	    mpx <= 0;
	    rdy <= 0;
	    S2 <= GP11w;
	  end
	end
  GP11w:
	S2 <= GP01;
  endcase
end
/////
always @(posedge clock)
begin
  if (reset)
  begin
 	load <= 0; 
	send <= 0;
	confirm <= 0;
	itfc_state <= G_IDLE;
  end
  else
  case (itfc_state)
  G_IDLE:
	if (shot)
	begin
	  load <= 1;
	  confirm <= 0;
	  itfc_state <= G_LOAD;
	end
	else
	begin
	  confirm <= 0;
	  itfc_state <= G_IDLE;
	end
  G_LOAD:
	begin
	  load <= 0;
	  send <= 1;
	  itfc_state <= G_SEND;
	end
  G_SEND:
	begin
	  send <= 0;
	  itfc_state <= G_WAIT_END;
	end
  G_WAIT_END:
	if (tx_end)
	begin
	  confirm <= 1;
	  itfc_state <= G_IDLE;
	end
  endcase
end

/////

always @(posedge clock)
begin
  if (reset)
  begin
	send_en <= 0;
	out_reg <= 8'b00000000;
	tre <= 0;
	error <= 0;
  end
  else
  begin
	if (tx_end)
	begin
	  send_en <= 0;
	  tre <= 1;
	end

	if (load)
	begin
	  if (!tre)
	  begin
	    out_reg <= data_in;
	    tre <= 1;
	    error <= 0;
	  end
	  else
	    error <= 1;
	end

	if (send)
	begin
	  if (!tre || !dsr)
	    error <= 1;
	  else
	  begin
	    error <= 0;		
	    send_en <= 1;
	  end
	end
  end
end

/////

parameter DelayTime=104;
	
always @(posedge clock)
begin
  if (reset)
  begin
	tx_end <= 0;
	data_out <= 0;
	next_bit <= START_BIT;
	tx_conta <= 0;
  end
  else
  begin
	tx_end <= 0;
	data_out <= 1;
	if (send_en)
	begin
	  if (tx_conta > DelayTime)
	  begin
	    case (next_bit)
		START_BIT:
		begin
		  data_out <= 0;
		  next_bit <= BIT0;
		end
		BIT0:
		begin
		  data_out <= out_reg[ 7 ];
		  next_bit <= BIT1;	
		end
		BIT1:
		begin
		  data_out <= out_reg[ 6 ];
		  next_bit <= BIT2;	
		end
		BIT2:
		begin
		  data_out <= out_reg[ 5 ];
		  next_bit <= BIT3;	
		end
		BIT3:
		begin
		  data_out <= out_reg[ 4 ];
		  next_bit <= BIT4;	
		end
		BIT4:
		begin
		  data_out <= out_reg[ 3 ];
		  next_bit <= BIT5;	
		end
		BIT5:
		begin
		  data_out <= out_reg[ 2 ];
		  next_bit <= BIT6;	
		end
		BIT6:
		begin
		  data_out <= out_reg[ 1 ];
		  next_bit <= BIT7;	
		end
		BIT7:
		begin
		 data_out <= out_reg[ 0 ];
		 next_bit <= STOP_BIT;	
		end
		STOP_BIT:
		begin
		  data_out <= 1;
		  next_bit <= START_BIT;
		  tx_end <= 1;
		end
	      endcase
	      tx_conta <= 0;
	    end
	    else
	      tx_conta <= tx_conta+1;
	end
  end
end
endmodule
